package com.yzg.sign.project.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yzg.sign.project.common.CheckUtil;
import com.yzg.sign.project.common.Result;
import com.yzg.sign.project.domain.SysUser;
import com.yzg.sign.project.exception.NormalException;

import com.yzg.sign.project.request.LoginForm;
import com.yzg.sign.project.request.UserAddAndEditRequest;
import com.yzg.sign.project.shiro.ShiroUtils;
import com.yzg.sign.project.common.HttpClientUtil;
import com.yzg.sign.project.repository.SysUserRepository;
import com.yzg.sign.project.service.SysUserService;
import com.yzg.sign.project.token.TokenUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.*;

@Service
@Transactional
public class SysUserServiceImpl implements SysUserService
{

     @Autowired
     private SysUserRepository sysUserRepository;

     @Autowired
     private TokenUtils tokenUtils;

     @Value("${weixin.appId}")
     private String appId;

     @Value("${weixin.appSecret}")
     private String appSecret;

    @Override
    public Result<String> saveOrUpdate(UserAddAndEditRequest request)
    {
        SysUser sysUser = null;
        if (request.getId() == null) {
            Optional<SysUser> result = sysUserRepository.findByUserNameAndDeleteIsFalse(request.getUserName());
            if (result.isPresent()) {
                return Result.<String>builder().fail().message("用户名重复").build();
            }
            if (StringUtils.isNotEmpty(request.getPhone())) {
                Optional<SysUser> sysUserOptional = sysUserRepository.findByPhoneAndDeleteIsFalse(request.getPhone());
                if (sysUserOptional.isPresent()) {
                    return Result.<String>builder().fail().message("手机号已存在！").build();
                }
            }
            sysUser = new SysUser();
            sysUser.setSalt(RandomStringUtils.randomAlphanumeric(6));
            ByteSource salt = ByteSource.Util.bytes(sysUser.getSalt());
            String password;
            if (StringUtils.isEmpty(request.getPassword())) {
                password = new SimpleHash("MD5", "123456", salt, 1024).toHex();
            } else {
                password = new SimpleHash("MD5", request.getPassword(), salt, 1024).toHex();
            }
            sysUser.setPassword(password);
        } else {
            Optional<SysUser> sysUserOptional1 = sysUserRepository.findByIdAndDeleteIsFalse(request.getId());
            if (sysUserOptional1.isPresent()) {
                sysUser = sysUserOptional1.get();
            } else {
                return Result.<String>builder().fail().message("对象不存在！").build();
            }
            if (!sysUser.getUserName().equals(request.getUserName()) && StringUtils.isNotEmpty(request.getUserName())) {
                Optional<SysUser> result = sysUserRepository.findByUserNameAndDeleteIsFalse(request.getUserName());
                if (result.isPresent()) {
                    return Result.<String>builder().fail().message("用户名重复").build();
                }
            }
            if (StringUtils.isNotEmpty(request.getPhone()) && !request.getPhone().equals(sysUser.getPhone())) {
                Optional<SysUser> sysUserOptional = sysUserRepository.findByPhoneAndDeleteIsFalse(request.getPhone());
                if (sysUserOptional.isPresent()) {
                    return Result.<String>builder().fail().message("手机号已存在！").build();
                }
            }
        }
        sysUser.setPhone(request.getPhone());
        sysUser.setUserName(request.getUserName());
        sysUser.setAvailable(request.getAvailable());
        sysUser.setRole(request.getRole());
        sysUserRepository.save(sysUser);
        return Result.<String>builder().success().build();
    }

    @Override
    public Result<Page<SysUser>> getUserPage(Map<String, String> params)
    {
        Sort sort = Sort.by("created").descending();
        Specification<SysUser> specification = getWhereClause(params);
        Pageable pageable = PageRequest.of(Integer.parseInt(params.get("pageNum")) - 1, Integer.parseInt(params.get("rows")),sort);
        Page<SysUser> sysUserPage = sysUserRepository.findAll(specification,pageable);
        return Result.<Page<SysUser>>builder().success().data(sysUserPage).build();
    }


    @Override
    public Result<String> delete(Integer id)
    {
        Optional<SysUser> sysUserOptional = sysUserRepository.findByIdAndDeleteIsFalse(id);
        if (!sysUserOptional.isPresent()) {
            throw new NormalException("用户不存在");
        }
        SysUser sysUser = sysUserOptional.get();
        sysUser.setDelete(true);
        sysUserRepository.save(sysUser);
        return Result.<String>builder().success().build();
    }

    @Override
    public Result<String> loginByPassword(LoginForm loginForm)
    {
        Optional<SysUser> sysUserOptional;
        if (CheckUtil.phoneFormat(loginForm.getUsername())) {
            sysUserOptional = sysUserRepository.findByPhoneAndDeleteIsFalseAndAvailableIsTrue(loginForm.getUsername());
        } else {
            sysUserOptional = sysUserRepository.findByUserNameAndDeleteIsFalseAndAvailableIsTrue(loginForm.getUsername());
        }
        if (!sysUserOptional.isPresent()) {                                                  //判断用户是否存在
            throw new NormalException("用户不存在");
        }
        SysUser sysUser = sysUserOptional.get();
        ByteSource salt = ByteSource.Util.bytes(sysUser.getSalt());
        String newPs = new SimpleHash("MD5", loginForm.getPassword(), salt, 1024).toHex();
        if (!newPs.equals(sysUser.getPassword())) {                                           //判断密码是否相等
            throw new NormalException("密码错误");
        } else {
            String token = tokenUtils.generateTokeCode(sysUser, String.valueOf(sysUser.getId()));
            if (sysUser.getLoginTimeNow() != null) {
                sysUser.setLoginTimeBefore(sysUser.getLoginTimeNow());
            }
            sysUser.setLoginTimeNow(new Date());
            sysUserRepository.saveAndFlush(sysUser);
            return Result.<String>builder().success().data(token).build();
        }
    }

    @Override
    public Result<SysUser> getUserInfo()
    {
        return null;
    }


    @Override
    public Result<String> loginOut()
    {
        ShiroUtils.logout();
        return Result.<String>builder().success().build();
    }

    @Override
    public Result<String> code2Session(String code)
    {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
        url = url.replace("APPID",appId).replace("SECRET",appSecret).replace("JSCODE",code);
        String res = HttpClientUtil.doGet(url);
        return Result.<String>builder().success().data(res).build();
    }

    private Specification<SysUser> getWhereClause(Map<String, String> params)
    {
        return  new Specification<SysUser>()
        {
            @Override
            public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)
            {
                List<Predicate> predicates = new ArrayList<Predicate>();
                List<Predicate> predicates1 = new ArrayList<Predicate>();
                if(!StringUtils.isEmpty(params.get("searchParam")))
                {
                    predicates.add(criteriaBuilder.equal(root.get("userName").as(String.class),params.get("searchParam")));
                }
                if (!StringUtils.isEmpty(params.get("searchParam")))
                {
                    predicates.add(criteriaBuilder.equal(root.get("phone").as(String.class),params.get("searchParam")));
                }
                predicates1.add(criteriaBuilder.equal(root.get("delete").as(Integer.class), 0));
                Predicate[] pre1 = new Predicate[predicates1.size()];
                Predicate[] pre = new Predicate[predicates.size()];
                if(pre.length==0)
                {
                    return criteriaQuery.where(criteriaBuilder.and(predicates1.toArray(pre1))).getRestriction();
                }
                return criteriaQuery.where(criteriaBuilder.or(predicates.toArray(pre)),criteriaBuilder.and(predicates1.toArray(pre1))).getRestriction();
            }
        };

    }
}
